package com.service.totalauth.service.impl;

import com.service.config.dto.MailBean;
import com.service.config.dto.ScreenUserDto;
import com.service.config.dto.SiteDto;
import com.service.config.utils.*;
import com.service.totalauth.controller.ManageInfoController;
import com.service.totalauth.dao.ManageInfoDao;
import com.service.totalauth.dao.PortalUserDao;
import com.service.totalauth.dto.*;
import com.service.totalauth.entity.ManageInfo;
import com.service.totalauth.entity.PortalUser;
import com.service.totalauth.service.FeginMstscUnique;
import com.service.totalauth.service.ManageInfoService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;

import static com.service.config.constant.Constant.USERNAME_REPEAT;
import static com.service.config.utils.CharUtil.getCharAndNumr;
import static com.service.totalauth.util.TransformationIp.getRealIp;

/**
 * 管理人员表(ManageInfo)表服务实现类
 *
 * @author makejava
 * @since 2021-08-10 16:14:21
 */
@Service("manageInfoService")
@Slf4j
public class ManageInfoServiceImpl implements ManageInfoService {
    @Resource
    private ManageInfoDao manageInfoDao;

    @Resource
    private RedisUtil redisUtil;
    @Autowired
    RedisTemplate redisTemplate;
    @Resource
    RestTemplate restTemplate;
    @Resource
    ManageInfoController manageInfoController;
    @Resource
    FeginMstscUnique feginMstscUnique;
    @Resource
    PortalUserDao portalUserDao;

    @Value("${Spring.http.url}")
    private String url;
    @Resource
    private CloudCampusApi cloudCampusApi;
    /**
     * 通过ID查询单条数据
     *
     * @param id 主键
     * @return 实例对象
     */
    @Override
    public ManageInfo queryById(String id) {
        return this.manageInfoDao.queryById(id);
    }

    /**
     * 查询多条数据
     *
     * @param offset 查询起始位置
     * @param limit  查询条数
     * @return 对象列表
     */
    @Override
    public List<ManageInfo> queryAllByLimit(int offset, int limit) {
        return this.manageInfoDao.queryAllByLimit(offset, limit);
    }

    /**
     * 新增数据
     *
     * @param manageInfo 实例对象
     * @return 实例对象
     */
    @Override
    public ManageInfo insert(ManageInfo manageInfo) {
        this.manageInfoDao.insert(manageInfo);
        return manageInfo;
    }

    /**
     * 修改数据
     *
     * @param manageInfo 实例对象
     * @return 实例对象
     */
    @Override
    public ManageInfo update(ManageInfo manageInfo) {
        this.manageInfoDao.update(manageInfo);
        return manageInfo;
    }

    /**
     * 通过主键删除数据
     *
     * @param id 主键
     * @return 是否成功
     */
    @Override
    public boolean deleteById(String id) {
        return this.manageInfoDao.deleteById(id) > 0;
    }

    /**
     * 用户登录获取token
     * @param loginUserDto
     * @param httpServletRequest
     * @return
     * @throws Exception
     */
    @Override
    public HashMap getToken(LoginUserDto loginUserDto, HttpServletRequest httpServletRequest) throws Exception {
        HashMap map = new HashMap();
        ManageInfo manageInfo = manageInfoDao.queryUserInfo(loginUserDto.getAccount(), loginUserDto.getPassword());
        if (manageInfo == null) {
                return null;
        }
        if (manageInfo.getStatus().equals("2") || manageInfo.getStatus().equals("3")) {
            map.put("errorCode","您的账号已被封号，详情请查看您的邮箱");
            return map;
        }
        return getHashMap(loginUserDto, httpServletRequest, map, manageInfo);

    }

    @Override
    public ManageInfo queryByUserName(UserInfoDto userInfoDto) throws Exception {
        return getUserInfoDto(userInfoDto);
    }

    @Override
    public ManageInfo register(UserInfoDto userInfoDto, String realIp) {
        return getUserInfo(userInfoDto,realIp);
    }

    @Override
    public Result simplifyRegister(SimplifyUserInfoDto simplifyUserInfoDto, String realIp) throws Exception {
        return getResult(simplifyUserInfoDto, realIp);
    }

    @Override
    public void sendMail(MailBean mailBean) {

    }

    @Override
    public ManageInfo queryByUserId(String manageId) {
        return null;
    }

    @Override
    public Map check(CheckTenantDto checkTenantDto, String userId) throws Exception {
        return check1(checkTenantDto,userId);
    }

    @Override
    public ManageInfo queryBySecret(String secret) {
        return manageInfoDao.queryBySecret(secret);
    }

    @Override
    @Transactional
    public ManageInfo freshSecret(String userId) {
        ManageInfo manageInfo = new ManageInfo();
        manageInfo.setId(userId);
        manageInfo.setSecret(verGetCharAndNumber(16));
        manageInfoDao.update(manageInfo);
        return this.queryById(userId);
    }


    /**
     * 校验云管api
     * @param checkTenantDto
     * @return
     */
    public Map check1(CheckTenantDto checkTenantDto, String userId) throws Exception {
        Map<String, Object>  map = new HashMap();
        PortalUser screenUser = new PortalUser();
        screenUser.setManageId(userId);
        screenUser.setTenantName(checkTenantDto.getUsername());
        List<PortalUser> screenUsers = portalUserDao.queryAll(screenUser);
        //该账号是否存在
        if (screenUsers.size() > 0) {
            map.put("errorMsg","关联华为云管理账号已存在");
        }else {
            HttpHeaders requestHeaders = new HttpHeaders();
            MediaType type = MediaType.parseMediaType("application/json; charset=UTF-8");
            requestHeaders.setContentType(type);
            requestHeaders.add("Accept", MediaType.APPLICATION_JSON.toString());
            TokenIdDto token = cloudCampusApi.getToken1(checkTenantDto.getUsername(), checkTenantDto.getPassword(), requestHeaders, checkTenantDto.getDomain());
            //String token = getToken(checkTenantDto.getUsername(), checkTenantDto.getPassword(), requestHeaders, checkTenantDto.getDomain());
            if (token == null) {
                map.put("errorMsg", "华为云管理账号不存在");
            } else {
                //获取站点
                requestHeaders.add("X-AUTH-TOKEN", token.getToken_id());
                String domain="";
                if (null != token.getRegionAddress() && !"".equals(token.getRegionAddress())) {
                    domain = token.getRegionAddress();
                } else {
                    domain = checkTenantDto.getDomain() + ".naas.huaweicloud.com";
                }
                List<SiteDto> sites = cloudCampusApi.getSites(requestHeaders, domain);
                if (sites != null && sites.size() > 0) {
                    token.setRegionAddress(domain);
                    map = JsonXMLUtils.json2map(JsonXMLUtils.obj2json(token));
                    return map;
                }
                map.put("errorMsg", "该账号为租户账号，请使用正确的Api账号");
            }
        }
        return map;
    }



    /**
     * 抽取公共代码
     * @param simplifyUserInfoDto
     * @param realIp
     * @return
     */
    private Result getResult(SimplifyUserInfoDto simplifyUserInfoDto, String realIp) throws Exception {
        HashMap map = new HashMap();
        ManageInfo userInfo = manageInfoDao.queryUserByName(simplifyUserInfoDto.getApiUsername());
        if (userInfo != null) {
            return Result.failure(USERNAME_REPEAT,"用户名已存在，请重新输入");
        }else {
            CheckTenantDto checkTenantDto = new CheckTenantDto();
            checkTenantDto.setDomain(simplifyUserInfoDto.getApiAddress());
            checkTenantDto.setPassword(simplifyUserInfoDto.getApiPassword());
            checkTenantDto.setUsername(simplifyUserInfoDto.getApiUsername());
            UserInfoDto userInfo1 = new UserInfoDto();
            userInfo1.setUsername(simplifyUserInfoDto.getApiUsername());
            userInfo1.setPassword(simplifyUserInfoDto.getApiPassword());
            ManageInfo userInfo2 = getUserInfo(userInfo1, realIp); // 新增用户
            if (userInfo2 != null) {
                Map check = check(checkTenantDto,userInfo2.getId()); // 校验云管api
                if (check.containsKey("errorMsg")) {
                    manageInfoDao.deleteById(userInfo2.getId());
                    return Result.ok().setData(check);
                }
                TokenIdDto tokenIdDto = ModelMapperUtil.strictMap(map, TokenIdDto.class);
                simplifyUserInfoDto.setApiAddress(tokenIdDto.getRegionAddress());
                ScreenUserDto screenUserDto = testScreenUser(simplifyUserInfoDto, userInfo2);
                if (screenUserDto == null) {
                    portalUserDao.deleteById(screenUserDto.getId());
                    manageInfoDao.deleteById(userInfo2.getId());
                    return Result.failure(10013, "云管理api账号已经存在，请检查");
                }
                String token = UserTokenManager.generateToken(userInfo2.getId());
                UserDto userDto = ModelMapperUtil.strictMap(userInfo2, UserDto.class);
                userDto.setIp(realIp); // 来源ip
                userDto.setDate(new Date()); //登录时间
                redisUtil.setValue(token + userInfo2.getId(), JsonXMLUtils.obj2json(userInfo2)); // 存入缓存
                map.put("Token", token);
                map.put("success", "您已注册成功，请等待一段时间会有数据刷新");
                return Result.ok().setData(map);
            }
        }
        return Result.failure(USERNAME_REPEAT,"用户名已存在，请重新输入");
    }

    /**
     * 校验api账号是否存在
     * @param simplifyUserInfoDto
     * @param userInfo2
     * @return
     */
    private ScreenUserDto testScreenUser(SimplifyUserInfoDto simplifyUserInfoDto,ManageInfo userInfo2){
        ScreenUserDto screenUser = new ScreenUserDto();
        screenUser.setTenantName(simplifyUserInfoDto.getApiUsername());
        screenUser.setDomain(simplifyUserInfoDto.getApiAddress());
        screenUser.setTenantPwd(simplifyUserInfoDto.getApiPassword());
        Result result = feginMstscUnique.addApiAccount();
        if (result.getCode() == 200) {
            screenUser.setId(result.getData().toString());
        }else {
            screenUser.setId(IdUtil.getStringId());
        }
        screenUser.setUserId(userInfo2.getId());
        PortalUser screenUser1 = ModelMapperUtil.strictMap(screenUser, PortalUser.class);
        List<PortalUser> screenUsers = portalUserDao.queryAll(new PortalUser());

        //该账号是否存在
        if (screenUsers.size() > 0) {
            Boolean flag = screenUsers.stream().anyMatch(task -> task.getTenantName().equals(screenUser.getTenantName()));
            if (flag) {
                return null;
            }
        }
        screenUser1.setStatus(true);
        screenUser1.setManageId(userInfo2.getId());
        portalUserDao.insert(screenUser1);
        return screenUser;
    }
    /**
     * 根据强制登录标识符获取token
     * 强制标识符不存在且没有用户登录则直接返回token
     * 用户已登陆则直接返回用户重复登录码
     * @param loginUserDto
     * @param httpServletRequest
     * @param map
     * @param manageInfo
     * @return
     * @throws Exception
     */
    private HashMap getHashMap(LoginUserDto loginUserDto, HttpServletRequest httpServletRequest, HashMap map, ManageInfo manageInfo) throws Exception {
        String realIp = getRealIp(httpServletRequest);
        UserDto userDto = ModelMapperUtil.strictMap(manageInfo, UserDto.class);
        userDto.setIp(realIp); // 来源ip
        userDto.setDate(new Date()); //登录时间
        String token = "";
        Boolean isLogin = loginUserDto.getIsLogin();
        Set<String> strings = redisUtil.redisLike(manageInfo.getId());
        if (isLogin != null) {
            if (isLogin) { // 强制登录标识符
                token = UserTokenManager.generateToken(manageInfo.getId());
                manageInfoController.clearCache(strings, redisUtil);
                HashMap map1 = setUserInfo(map, manageInfo, userDto, token);
                return map1;
            }
        }
        if (strings.size() >= 1) {
            map.put("errorCode","用户重复登陆");
            return map ;
        }else {
            token = UserTokenManager.generateToken(manageInfo.getId());
            HashMap map1 = setUserInfo(map, manageInfo, userDto, token); //更新用户信息
            return map1;
        }
    }

    /**
     * 更新用户信息并返回token
     * @param map
     * @param manageInfo
     * @param userDto
     * @param token
     * @return
     * @throws Exception
     */
    private HashMap setUserInfo(HashMap map, ManageInfo manageInfo, UserDto userDto, String token) throws Exception {
        manageInfo.setCount(manageInfo.getCount()+1);
        manageInfo.setDate(userDto.getDate());
        manageInfo.setIp(userDto.getIp());
        manageInfoDao.update(manageInfo);
        redisUtil.setValue(token+manageInfo.getId(), JsonXMLUtils.obj2json(userDto)); // 存入缓存
        map.put("Token",token);
        return map;


    }

    /**
     * 用户名获取邮箱用于密码找回
     * @param username
     * @return
     * @throws Exception
     */
    private ManageInfo getUserInfoDto(UserInfoDto username) throws Exception {
        UserInfoDto userInfoDto = new UserInfoDto();
        MailBean mailBean = new MailBean();
        ManageInfo userInfo = manageInfoDao.queryUserByName(username.getUsername());
        if (userInfo != null) {
            if (userInfo.geteMail() != null && !userInfo.geteMail().equals("")
                    && userInfo.geteMail().contains("@")) { // 邮箱是否存在格式是否正确
                String random = getRandom(6);
                mailBean.setSubject("密码找回，请点击链接进行操作");
                mailBean.setRecipient(userInfo.geteMail());
                mailBean.setContent("您的验证码：" + random + "\r\n" + "请点击下列链接并填写验证码：" + url);
                userInfoDto = JsonXMLUtils.json2obj(JsonXMLUtils.obj2json(userInfo), UserInfoDto.class);
                redisUtil.set(random, 1, JsonXMLUtils.obj2json(userInfoDto), 10); // 缓存两分钟有效
                redisTemplate.convertAndSend("sendEmail", mailBean); // 发送邮件
                return userInfo;
            }
        }
        return null;
    }

    /**
     *  新增用户
     * @param userInfoDto
     * @param realIp
     * @return
     */
    private ManageInfo getUserInfo(UserInfoDto userInfoDto, String realIp) {
        ManageInfo userInfo = ModelMapperUtil.strictMap(userInfoDto,ManageInfo.class);
        ManageInfo userInfo1 = manageInfoDao.queryUserByName(userInfo.getUsername());
        if (userInfo1 != null) {
            return null;
        }
        Result result = feginMstscUnique.addApiAccount();
        if (result.getCode() == 200) {
            userInfo.setId(result.getData().toString());
        }else {
            userInfo.setId(IdUtil.getStringId());
        }
        userInfo.setIp(realIp);
        userInfo.setAddTime(new Date());
        userInfo.setDate(new Date());
        userInfo.setCount(1);
        userInfo.setStatus(0);
        userInfo.setSecret(verGetCharAndNumber(16));
        manageInfoDao.insert(userInfo);
        return userInfo;
    }

    private String verGetCharAndNumber(int i) {
        ManageInfo manageInfo = new ManageInfo();
        manageInfo.setSecret(getCharAndNumr(i));
        List<ManageInfo> manageInfos = manageInfoDao.queryAll(manageInfo);
        if (manageInfos.size() > 0) {
            verGetCharAndNumber(i);
        }
        return manageInfo.getSecret();
    }

    /**
     * 递归查询缓存中存在验证码
     * @return
     */
    private  String getRandom(Integer i){
        String randomNum = "";
        if (i == null) {
            randomNum = CharUtil.getRandomNum(6);
        }else {
            randomNum = CharUtil.getRandomNum(i);
        }
        if (redisUtil.exist(randomNum)) {
            getRandom(i);
        }
        return randomNum;
    }
}
